/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include <向量.h>

#include "引擎数据类型.h"
#include "S_Object.h"
#include "core/设备内存缓存.h"



#define DEF_骨骼朝向 (vec3{ 0, 0, 1 })


typedef void(*fn_mesh绘制参数设置)(S_Mesh* me, const S_GPU内存块* 物体参数[2], uint32 多维子元素);
typedef vec3(*fp_坐标转换)(const vec3& vert);

typedef void(*fn_物体网格绘制参数设置)(S_Object* ob, S_网格包& me, uint32 多维子元素);





typedef enum {
	e_顶点坐标	= 1 << 1,
	e_顶点法线	= 1 << 2,
	e_顶点UV	= 1 << 3,
	e_顶点颜色	= 1 << 4,
	e_顶点权重	= 1 << 5,
	e_空间曲线	= 1 << 6,
	e_AABB		= 1 << 7,
}E_顶点标志位;

#define DEF_Vert预设_vn		E_顶点标志位::e_顶点坐标| E_顶点标志位::e_顶点法线
#define DEF_Vert预设_vnu	E_顶点标志位::e_顶点坐标| E_顶点标志位::e_顶点法线 | E_顶点标志位::e_顶点UV


typedef enum {
	e_坐标 = E_顶点标志位::e_顶点坐标,
	e_坐标_法线 = E_顶点标志位::e_顶点坐标 | E_顶点标志位::e_顶点法线,
	e_坐标_法线_UV = E_顶点标志位::e_顶点坐标 | E_顶点标志位::e_顶点法线 | E_顶点标志位::e_顶点UV,
	e_坐标_法线_UV_颜色,
	e_坐标_UV,
	e_坐标_颜色 = E_顶点标志位::e_顶点坐标 | E_顶点标志位::e_顶点颜色,
	e_坐标_权重,
	e_包围盒 = E_顶点标志位::e_AABB,
	
}E_顶点组合标志;



enum class E_网格缓存元素位域 : uint32 {
	e_顶点坐标	= 1 << 1,
	e_顶点法线	= 1 << 2,
	e_顶点UV	= 1 << 3,
	e_顶点索引	= 1 << 4,
	e_顶点颜色	= 1 << 5,
	e_顶点权重	= 1 << 6,
	e_面材质ID	= 1 << 7,
};









struct S_Mesh板载缓存 {
	S_板载缓存* m_顶点;
	S_板载缓存* m_法线;
	S_板载缓存* m_颜色;
	S_板载缓存* m_索引;
	//S_板载缓存* m_权重;
	S_板载缓存* m_间接;

	S_板载缓存* m_UV1;
	S_板载缓存* m_UV索引;
	//S_骨骼*		m_骨骼;
	uint32		m_顶点配置Flags;

	S_Mesh板载缓存() : m_顶点(0), m_法线(0), m_颜色(0), m_索引(0), m_间接(0), m_UV1(0), m_顶点配置Flags(0)
	{
	}

	virtual void	f_填充顶点(const std::vector<vec3>& v, S_设备环境& ctx) = 0;
	virtual void	f_填充法线(const std::vector<vec3>& n, S_设备环境& ctx) = 0;
	virtual void	f_填充颜色(const std::vector<ubvec4>& c, S_设备环境& ctx) = 0;
	virtual void	f_填充索引(const std::vector<uint32>& index, S_设备环境& ctx) = 0;

	virtual void	f_填充UV(const std::vector<vec2>& uv1, uint8 纹理层, S_设备环境& ctx) = 0;

};





EngineAPI_EXPORT void f_me_init材质槽(S_管线槽* 材质槽, uint32 num);
EngineAPI_EXPORT void f_me_alloc多维材质槽(S_Mesh* me, uvec2* 索引区间, uint32 num, S_材质管线* 默认材质);
EngineAPI_EXPORT void f_me_free多维材质槽(S_Mesh* me);
EngineAPI_EXPORT void f_me_free多维元素槽(S_Mesh* me);

struct EngineAPI_EXPORT S_Mesh : public S_Object {
	S_设备环境	m_Ctx;

	S_元素绘制类型		m_绘制类型;
	E_网格预设类型		m_预设类型;
	E_网格数据枚举		m_Tye;
	E_绘制方式			m_网格类型;
	


	S_GPU内存块* m_顶点;
	S_GPU内存块* m_颜色;
	S_GPU内存块* m_UV;
	S_GPU内存块* m_UV索引;
	S_GPU内存块* m_索引;
	S_GPU内存块* m_面;
	S_GPU内存块* m_面属性;

	S_GPU内存块* m_邻接面索引;
	S_GPU内存块* m_面法线;
	S_GPU内存块* m_面中心;
	S_GPU内存块* m_间接;

	S_GPU内存块* m_顶点骨骼属性;
	S_GPU内存块* m_骨骼权重映射;
	
	


	S_GPU内存块		m_网格元素变换属性;
	S_GPU内存块*	m_网格属性;

	S_GPU内存块*	m_底层光追加速结构;
	S_GPU内存块		m_光追网格GPU地址引用;
	uint32			m_光追网格ID;
	uint32			m_光追图元更新偏移;
	uint32			m_光追结构更新偏移;

	S_GPU内存块*	m_变换矩阵;

	fn_物体网格绘制参数设置 mf_参数设置回调;

	std::map<std::u16string, S_GPU内存块>* m_点自定义属性区间偏移;
	std::map<std::u16string, S_GPU内存块>* m_面自定义属性区间偏移;

	
	S_GPU内存块*	m_自定义属性索引;
	bool			m_自定义属性链接;
	
	std::vector<S_GPU内存块> m_自定义参数;

	
	
	S_UI32Array*    m_材质槽ID;
	
	S_网格元素*		m_元素;
	S_管线槽*		m_多维材质槽;
	uint32			m_多维材质数量;

	S_Bounding*		m_Bound;
	//变换后
	S_Cube*			m_包围盒;


	uint32*	m_顶点配置Flags;
	void*	m_绘制内存属性;
	uint32	m_绘制属性字节大小;
	uint32	m_绘制属性绑定阶段;

	uint32	m_顶点数量;

	
	S_板载缓存* m_姿态变换;
	S_板载缓存* m_选中骨骼ID;

	uint32 uvLayerNum;
	uint32 uvLayerOffset;

	uint32 m_间接绘制偏移;
	uint32 m_间接绘制数量;
	
	vec2	m_深度控制;
	float32	m_线宽;
	

	bool m_关联顶点;
	bool m_关联索引;
	bool m_关联权重;
	bool m_关联颜色;
	bool m_关联UV;
	
	
	S_RGBA8UI		m_Color;

	S_ObMesh		m_几何属性;
	
	bool			m_拾取;
	bool			m_显示;
	bool			m_是否链接;
	bool			m_更新光追加速结构;

	uint8			m_顶点变换模式;
	uint8			m_片源着色模式;


	fn_mesh绘制参数设置		mf_绘制参数设置;

	

	S_Mesh(S_Mesh* me=0) : S_Object(E_物体类型::t_网格缓存) {
		m_Tye = E_网格数据枚举::e_Mesh_CPU;
		m_预设类型 = E_网格预设类型::e_网格预设_未知;
		m_片源着色模式 = DEF_3DShaderType_PerObColor;
		m_顶点变换模式 = DEF_3DTranform_Normal;

		m_绘制类型		= S_元素绘制类型::e_绘制类型_结束;
		m_顶点配置Flags = nullptr;
		m_线宽          = 1.0;
		m_拾取			= true;
		m_显示          = true;
		m_是否链接      = false;
		m_更新光追加速结构 = true;

		m_包围盒 = nullptr;
		m_Bound = nullptr;

		m_深度控制      = { 1, 0 };
		m_几何属性      = {};
		

		m_颜色   = nullptr;
		m_顶点   = nullptr;
		m_索引   = nullptr;
		//m_UV     = nullptr;
		m_UV     = {};
		m_UV索引 = {};

		m_网格元素变换属性 = {};
		


		m_底层光追加速结构		= nullptr;
		m_光追网格GPU地址引用	= {};
		m_光追网格ID			= 0;
		m_光追图元更新偏移		= 0;
		m_光追结构更新偏移		= 0;


		//m_文字ID = 0;
		m_点自定义属性区间偏移 = nullptr;
		m_面自定义属性区间偏移 = nullptr;
		m_自定义属性索引 = {};
		m_自定义属性链接 = false;
		

		m_间接     = nullptr;
		m_绘制内存属性 = nullptr;
		m_绘制属性字节大小 = 0;
		m_绘制属性绑定阶段 = E_着色阶段::e_顶点着色;

		m_姿态变换 = nullptr;
		m_顶点骨骼属性 = nullptr;
		m_骨骼权重映射 = nullptr;
		
		m_选中骨骼ID     = nullptr;
		m_面             = nullptr;

		m_网格属性		= nullptr;
		m_邻接面索引	= nullptr;
		m_面法线		= nullptr;
		m_面中心		= nullptr;


		m_关联顶点 = false;
		m_关联索引 = false;
		m_关联权重 = false;
		m_关联颜色 = false;
		m_关联UV = false;

		m_Color	= {0,0,0,255};

		m_元素 = nullptr;
		m_多维材质槽 = nullptr;
		m_多维材质数量 = 0;
		static uvec2 temp{};
		f_me_alloc多维材质槽(this, &temp, 1, nullptr);


		m_间接绘制偏移 = 0;
		m_间接绘制数量 = 0;
		m_材质槽ID = nullptr;
		m_网格类型 = E_绘制方式::e_三角形;

		mf_绘制参数设置 = nullptr;
	}
	virtual ~S_Mesh(){
		f_me_free多维材质槽(this);
	}


	//void operator = (S_Mesh* me) {
	//	++m_引用计数;
	//}
	

	virtual S_结构指针	f_get顶点() { return 0; };
	virtual S_结构指针	f_get颜色() { return 0; };
	virtual S_结构指针	f_get法线() { return 0; };
	virtual S_结构指针	f_get索引() { return 0; };


	virtual	void f_get顶点(S_结构指针 data) {};
	virtual	void f_get法线(S_结构指针 data) {};
	virtual	void f_get索引(S_结构指针 data) {};

	virtual	void f_get顶点(std::vector<vec3>& vert) const {};
	virtual	void f_get法线(std::vector<vec3>& normal) const {};
	virtual	void f_get索引(std::vector<uint32>& index) const {};
	virtual	void f_get颜色(std::vector<vec4>& index) const {};


	virtual void f_fill顶点(const vec3* xyz, uint32 num) {}
	virtual void f_fill法线(const vec3* normal, uint32 num) {}
	virtual void f_fill索引(const uint32* index, uint32 num) {}
	virtual void f_fillUV(const vec2* index, uint32 num, uint8 纹理层) {}
	virtual void f_fill权重(const float32* w, uint32 num) {}
	virtual void f_fill骨骼ID(const uint32* bid, uint32 num) {}
	//virtual void f_fill骨骼属性(const S_骨骼属性& 骨骼属性) {}


	virtual void f_fill法线(const std::vector<vec3>& normal) {}
	//virtual void f_fill索引(const std::vector<uint32>& index) {}
	virtual void f_fill颜色(const std::vector<S_RGBA8UI>& color) {}
	virtual void f_填充顶点数据(const std::vector<S_VN>& data) {}
	virtual void f_填充顶点数据(const std::vector<S_VC>& data) {}
	virtual uint32 f_填充顶点数据(uint16 bitSize, uint64 num, void* data) {return 0;}
	virtual uint32 f_填充顶点数据(void* data, uint64 num, uint32 顶点配置) { return 0; }

	virtual uint32 f_填充索引数据(uint16 bitSize, uint64 num, void* data) { return 0; }
	virtual uint32 f_fillUV索引数据(uint16 bitSize, uint32 num, const void* data) {return 0;}

	//virtual void f_set顶点(const S_UI32Array* index, const S_Vec3Array* xyz) {}
	//virtual void f_set法线(const S_UI32Array* index, const S_Vec3Array* normal) {}
	//void f_填充间接数据(const std::vector<S_VkDrawIndexedIndirectCommand>& indirect);
	virtual void f_重置顶点数量(uint64 num) {}
	virtual void f_Clear() {}
	virtual void f_Clear索引(){}
	virtual void f_计算包围盒() {}


	virtual	uint32		f_get顶点数量() { return 0; }
	virtual uint32		f_get索引数量() { return 0; }

	virtual void		f_AddMesh(const S_Mesh& m) {}
	//virtual void		f_to板载缓存() {}
	virtual void		f_clear板载缓存(){}
	
	
	//void				f_Transform(const C_Mat44& m);
	void				f_创建板载缓存族(E_绘图API engineType = E_绘图API::E_Vulkan);
	//vec3				f_拾取(const vec3& s, const vec3& e);


	virtual E_序列map	f_map法线() { return { 0, 0 }; };
	virtual E_序列map	f_map颜色() { return { 0, 0 }; };
	virtual E_序列map	f_mapUV(uint8 纹理层 = 0) { return { 0, 0 }; }
	virtual E_序列map	f_map索引() { return { 0, 0 }; }

	//virtual void			f_unmap顶点() {}
	virtual void			f_upmap法线() {}
	virtual void			f_upmap颜色() {}
	//virtual void			f_unmap索引() {}

	virtual void			f_upmapUV1() {}
	virtual void			f_upmapUV2() {}

	virtual void		f_updateGPU参数布局() {}
	virtual void		f_绘制(S_渲染参数& 渲染参数, uint32 多维子元素) {}
	

	S_Bounding& f_getBound(){
		return *m_Bound;
	}
	S_Cube& f_get包围盒() { 
		return *m_包围盒; 
	}

protected:
	
private:
	E_绘图API m_板载缓存族;

};

Inline void f_me_setBound(S_Mesh* me, const S_Bounding& bound) {
	*me->m_Bound = bound;
}
Inline S_Bounding& f_me_getBound(const S_Mesh* me) {
	return *me->m_Bound;
}
Inline vec3 f_me_getBoundSize(const S_Mesh* me) {
	return me->m_Bound->max - me->m_Bound->min;
}

Inline void f_me_set包围盒(S_Mesh* me, const S_Cube& 包围盒) {
	*me->m_包围盒 = 包围盒;
}
Inline S_Cube& f_me_get包围盒(const S_Mesh* me) {
	return *me->m_包围盒;
}





int8 f_顶点配置标志(S_Mesh* mesh, E_顶点标志位 type);

void f_mesh_创建骨骼(S_Mesh* mesh, S_设备环境& ctx);

void f_mesh_创建颜色缓存(S_Mesh* mesh, S_设备环境& ctx);

Inline S_MeshTranformProp& f_mesh_get网格元素绘制属性(S_Mesh* mesh, uint32 offset = 0) {
	return f_buf_网格元素变换属性_at(mesh->m_网格元素变换属性, offset);
}

EngineAPI_EXPORT void f_mesh_切换顶点类型(S_Mesh* 目标, uint32 flags, uint32 num);

EngineAPI_EXPORT void f_me_alloc多维材质槽(S_Mesh* me, uint32 num, S_材质管线* 默认材质);
EngineAPI_EXPORT void f_me_set多维材质(S_Mesh* me, S_材质管线* 材质, uint32 元素索引, uint32 槽 = 0);

EngineAPI_EXPORT void f_me_分配光追几何(S_Mesh* me);

